(function($) {
    $.widget("ui.jsongrid", {
        _init: function() {
            var self = this, grid = this.element.hide().addClass('json-grid'), options = this.options;
            // create table title by `options.title`
            $('<div class="grid-title">'+options.title+'</div>').appendTo(grid);
            // create buttons by `options.buttons`
            if (options.buttons) {
                var buttons = $('<div class="grid-buttons"/>').appendTo(grid);
                $.each(options.buttons, function(i, btn) {
                    if (btn.separator) {
                        buttons.append('<div class="button-separator"/>');
                        return;
                    }
                    var box = $('<div class="grid-button"/>');
                    $('<div id="'+btn.name+'"/>').addClass(btn.cls)
                    .html(btn.display).click(btn.click).appendTo(box);
                    buttons.append(box);
                });
                buttons.append('<br class="clear"/>');
            }
            //
            var box = $('<div class="grid-box"><div class="col-drag"><div class="col-resize"/></div>').appendTo(grid);
            // create table head by `options.columns`
            var thead = $('<div class="grid-columns"><table cellspacing="0" cellpadding="0" border="1"><thead><tr/></thead></table></div>');
            var tr = thead.find('tr');
            // head cell: '<th><div style="text-align:${align}, width:${width}">${display}</div></th>'
            $.each(options.columns, function(i, col) {
                var th = $('<th/>').attr('id', col.name);
                // show columns resize element.
                th.mouseover(function(e) {
                    if (e.target == this) {
                        var t = $(this), left = t.offset().left + t.width();
                        if (left - e.pageX > 2 || self.colResize.is(':visible')) return;
                        //
                        self.colResize.css({
                            height: thead.height() + table.height(),
                            left: left
                        }).show();
                        self.colResize.colIndex = self.columns.index(t); 
                    }
                });
                //
                $('<div/>').css({
                    'text-align': col.align || 'left',
                    'width': (col.width || 50) + 'px',
                    'padding': '5px'
                }).html(col.display).appendTo(th);
                tr.append(th);
            });
            box.append(thead);
            // create grid 
            var table = $('<div class="grid-table"><table cellspacing="0" cellpadding="0" border="1"><tbody/></table></div>')
            .css({
                'height': options.height+'px', 
                'width': options.width === 'auto' ? options.width : options.width+'px'
            });
            box.append(table);
            // create table footer and pagination.
            var foot = $('<div class="grid-foot"/>').appendTo(grid);
            foot.html('<div class="pagination">'+
            '<div class="page-first"/> <div class="page-prev"/> <div class="button-separator"/>'+
            '<div class="page-number"><span>Page <input type="text" size="4" value="1" /> of <span> 1 </span></span></div>'+
            '<div class="button-separator"/>'+
            '<div class="page-next"/> <div class="page-last"/> <div class="button-separator"/>'+
            '<div class="page-reload"/> <div class="button-separator"/> <div class="page-message"/></div><br class="clear"/>');
            // bind pagination event
            $('.page-first', foot).click(function() { self.load(1); });
            $('.page-prev', foot).click(function() { if (options.page > 1) self.load(options.page - 1); });
            $('.page-number input', foot).keydown(function(e) {
                if (e.keyCode == 13) {
                    var v = parseInt(this.value);
                    if (isNaN(v)) {
                        this.value = options.page;
                        return;
                    }
                    if (v < 1 || v > options.pages) {
                        this.value = options.page;
                        return;
                    }
                    self.load(v);
                }
            });
            $('.page-next', foot).click(function() { if (options.page < options.pages) self.load(options.page + 1); });
            $('.page-last', foot).click(function() { self.load(options.pages); });
            $('.page-reload', foot).click(function() { self.load(); });
            //
            
            //
            grid.show();
            // cache some object.
            this.tbody = $('div.grid-table>table>tbody', this.element);
            this.columns = $('div.grid-columns th');
            this.colResize = $('div.col-resize', this.element).mouseout(function(){
                $(this).hide();
            }).draggable({
                axis: 'x',
                drag: function(e, ui) {
                    var index = self.colResize.colIndex, col = $(self.columns.get(index));
                    var w = e.pageX - col.offset().left - 10;
                    col.find('div').width(w);
                    self.tbody.find('td:eq('+index+')>div').width(w);
                }
            });
            //
            this.load();
            

        },
        load: function(page) {
            if (this.loading) return true;
            this.loading = true;
            if (!this.options.url) return false;

            var self = this, options = this.options;
            if (page) options.page = page;
            $.ajax({
                type: options.method || "GET",
                url: options.url,
                data: {
                    'page': options.page,
                    'size': options.size
                },
                dataType: 'json',
                success: function(data, textStatus) { self._full(data, textStatus); },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    self._ajaxError(XMLHttpRequest, textStatus, errorThrown) 
                }
            });
            // loading ...

        },
        _full: function(data, textStatus) {
            var self = this, options = this.options;
            //
            this.loading = false;
            if (!data) {
                this._message(options.dataErrorMessage);
                return;
            }
            this._clear();
            var total = data.count;
            if (total == 0) {
                options.page = 1
                options.pages = 1
                this._message(options.noMessage);
                return;
            }
            else {
                options.page = data.page;
                options.pages = Math.ceil(data.total/options.size);
                // add rows to table
                $.each(data.objects, function(i, row) {
                    self.addRow(row);
                });
                // update message
                var r = {
                    from: (options.page - 1) * options.size + 1,
                    to: options.page * options.size > total ? total: options.page * options.size,
                    total: total
                }
                var message = options.pageStatus.replace(/\${\w+}/g, function(word) {
                    var key = word.slice(2, -1);
                    return r[key];
                });
                this._message(message);
            }
            
        },
        addRow: function(data) {
            var options = this.options;
            var tr = $('<tr/>').click(function(){
                var row = $(this).toggleClass('grid-row-selected');
                if (!options.multiSelection) row.siblings().removeClass('grid-row-selected');
            });
            if (data.pk) tr.attr('id', data.pk);
            // create cell
            $('.grid-columns thead th', this.element).each(function() {
                var td = $('<td/>');
                $(this).children('div').clone().html(data[this.id]).appendTo(td);
                tr.append(td);
            })
            this.tbody.append(tr);
            return tr;
        },
        _ajaxError: function(XMLHttpRequest, textStatus, errorThrown) {
            this.loading = false;
            this._message(this.options.errorMessage + ', ' + textStatus);
        },
        _message: function(text) {
            $('.page-message', this.element).html(text);
        },
        _clear: function() {
            $('*', this.tbody).unbind();
            this.tbody.empty();
        }
    });

})(jQuery);

$.extend($.ui.jsongrid, {
    defaults: {
        height: 200,
        width: 'auto',
        resizable: true,
        url: false,
        method: 'POST',
        page: 1,
        size: 10,
        multiSelection: false,
        errorMessage: 'Connection error',
        pageStatus: 'Displaying ${from} to ${to} of ${total} items.',
        processMessage: 'Processing, please wait ...',
        noMessage: 'No items.',
        dataErrorMessage: 'request data error.'
    },
    
});


